home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / telnet.c < prev    next >
C/C++ Source or Header  |  1992-05-14  |  10KB  |  527 lines

  1. /* @(#) $Header: telnet.c,v 1.12 92/05/14 13:20:34 deyke Exp $ */
  2.  
  3. /* Internet Telnet client
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "socket.h"
  10. #include "telnet.h"
  11. #include "session.h"
  12. #include "proc.h"
  13. #include "icmp.h"
  14. #include "tcp.h"
  15. #include "tty.h"
  16. #include "commands.h"
  17. #include "netuser.h"
  18.  
  19. static void unix_send_tel __ARGS((char *buf, int n));
  20. static void send_tel __ARGS((char *buf, int n));
  21. static void tel_input __ARGS((struct telnet *tn, struct mbuf *bp));
  22. static void tn_tx __ARGS((struct tcb *tcb, int cnt));
  23. static void t_state __ARGS((struct tcb *tcb, int old, int new));
  24. static void free_telnet __ARGS((struct telnet *tn));
  25. static void willopt __ARGS((struct telnet *tn, int opt));
  26. static void wontopt __ARGS((struct telnet *tn, int opt));
  27. static void doopt __ARGS((struct telnet *tn, int opt));
  28. static void dontopt __ARGS((struct telnet *tn, int opt));
  29. static void answer __ARGS((struct telnet *tn, int r1, int r2));
  30.  
  31. #define CTLZ    26
  32.  
  33. int Refuse_echo = 0;
  34. int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  35.  
  36. #ifdef  DEBUG
  37. char *T_options[] = {
  38.     "Transmit Binary",
  39.     "Echo",
  40.     "",
  41.     "Suppress Go Ahead",
  42.     "",
  43.     "Status",
  44.     "Timing Mark"
  45. };
  46. #endif
  47.  
  48. /* Execute user telnet command */
  49. int
  50. dotelnet(argc,argv,p)
  51. int argc;
  52. char *argv[];
  53. void *p;
  54. {
  55.     struct session *s;
  56.     struct telnet *tn;
  57.     struct tcb *tcb;
  58.     struct socket lsocket,fsocket;
  59.  
  60.     lsocket.address = INADDR_ANY;
  61.     lsocket.port = Lport++;
  62.     if((fsocket.address = resolve(argv[1])) == 0){
  63.         printf(Badhost,argv[1]);
  64.         return 1;
  65.     }
  66.     if(argc < 3)
  67.         fsocket.port = IPPORT_TELNET;
  68.     else
  69.         fsocket.port = tcp_port_number(argv[2]);
  70.  
  71.     /* Allocate a session descriptor */
  72.     if((s = newsession()) == NULLSESSION){
  73.         printf("Too many sessions\n");
  74.         return 1;
  75.     }
  76.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  77.         strcpy(s->name,argv[1]);
  78.     s->type = TELNET;
  79.     if ((Refuse_echo == 0) && (Tn_cr_mode != 0)) {
  80.         s->parse = unix_send_tel;
  81.     } else {
  82.         s->parse = send_tel;
  83.     }
  84.     Current = s;
  85.  
  86.     /* Create and initialize a Telnet protocol descriptor */
  87.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  88.         printf(Nospace);
  89.         s->type = FREE;
  90.         return 1;
  91.     }
  92.     tn->session = s;        /* Upward pointer */
  93.     tn->state = TS_DATA;
  94.     s->cb.telnet = tn;      /* Downward pointer */
  95.  
  96.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  97.      rcv_char,tn_tx,t_state,0,(int)tn);
  98.  
  99.     tn->tcb = tcb;  /* Downward pointer */
  100.     go(argc, argv, p);
  101.     return 0;
  102. }
  103.  
  104. /* Process typed characters */
  105. static void
  106. unix_send_tel(buf,n)
  107. char *buf;
  108. int n;
  109. {
  110.     int i;
  111.  
  112.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  113.         ;
  114.     if (buf[i] == '\r') {
  115.         buf[i] = '\n';
  116.         n = i+1;
  117.     }
  118.     send_tel(buf,n);
  119. }
  120. static void
  121. send_tel(buf,n)
  122. char *buf;
  123. int n;
  124. {
  125.     struct mbuf *bp;
  126.     if(Current == NULLSESSION || Current->cb.telnet == NULLTN
  127.      || Current->cb.telnet->tcb == NULLTCB)
  128.         return;
  129.     /* If we're doing our own echoing and recording is enabled, record it */
  130.     if(!Current->cb.telnet->remote[TN_ECHO] && Current->record != NULLFILE)
  131.         fwrite(buf,1,n,Current->record);
  132.     bp = qdata(buf,n);
  133.     send_tcp(Current->cb.telnet->tcb,bp);
  134. }
  135.  
  136. /* Process incoming TELNET characters */
  137. static void
  138. tel_input(tn,bp)
  139. register struct telnet *tn;
  140. struct mbuf *bp;
  141. {
  142.     int c;
  143.     FILE *record;
  144.  
  145.     /* Optimization for very common special case -- no special chars */
  146.     if(tn->state == TS_DATA){
  147.         while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR){
  148.             if((record = tn->session->record) != NULLFILE)
  149.                 fwrite(bp->data,1,bp->cnt,record);
  150.             while(bp->cnt-- != 0)
  151.                 putchar(*bp->data++);
  152.             bp = free_mbuf(bp);
  153.         }
  154.     }
  155.     while((c = PULLCHAR(&bp)) != -1){
  156.         switch(tn->state){
  157.         case TS_DATA:
  158.             if(c == IAC){
  159.                 tn->state = TS_IAC;
  160.             } else {
  161.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  162.                     c &= 0x7f;
  163.                 putchar(c);
  164.                 if((record = tn->session->record) != NULLFILE)
  165.                     putc(c,record);
  166.             }
  167.             break;
  168.         case TS_IAC:
  169.             switch(c){
  170.             case WILL:
  171.                 tn->state = TS_WILL;
  172.                 break;
  173.             case WONT:
  174.                 tn->state = TS_WONT;
  175.                 break;
  176.             case DO:
  177.                 tn->state = TS_DO;
  178.                 break;
  179.             case DONT:
  180.                 tn->state = TS_DONT;
  181.                 break;
  182.             case IAC:
  183.                 putchar(c);
  184.                 tn->state = TS_DATA;
  185.                 break;
  186.             default:
  187.                 tn->state = TS_DATA;
  188.                 break;
  189.             }
  190.             break;
  191.         case TS_WILL:
  192.             willopt(tn,c);
  193.             tn->state = TS_DATA;
  194.             break;
  195.         case TS_WONT:
  196.             wontopt(tn,c);
  197.             tn->state = TS_DATA;
  198.             break;
  199.         case TS_DO:
  200.             doopt(tn,c);
  201.             tn->state = TS_DATA;
  202.             break;
  203.         case TS_DONT:
  204.             dontopt(tn,c);
  205.             tn->state = TS_DATA;
  206.             break;
  207.         }
  208.     }
  209. }
  210.  
  211. /* Telnet receiver upcall routine */
  212. void
  213. rcv_char(tcb,cnt)
  214. register struct tcb *tcb;
  215. int cnt;
  216. {
  217.     struct mbuf *bp;
  218.     struct telnet *tn;
  219.     FILE *record;
  220.  
  221.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  222.         /* Unknown connection; ignore it */
  223.         return;
  224.     }
  225.     /* Hold output if we're not the current session */
  226.     if(Mode != CONV_MODE || Current == NULLSESSION
  227.      || Current->type != TELNET || Current->cb.telnet != tn)
  228.         return;
  229.  
  230.     if(recv_tcp(tcb,&bp,cnt) > 0)
  231.         tel_input(tn,bp);
  232.  
  233.     if((record = tn->session->record) != NULLFILE)
  234.         fflush(record);
  235. }
  236. /* Handle transmit upcalls. Used only for file uploading */
  237. static void
  238. tn_tx(tcb,cnt)
  239. struct tcb *tcb;
  240. int16 cnt;
  241. {
  242.     struct telnet *tn;
  243.     struct session *s;
  244.     struct mbuf *bp;
  245.     int size;
  246.  
  247.     if((tn = (struct telnet *)tcb->user) == NULLTN
  248.      || (s = tn->session) == NULLSESSION
  249.      || s->upload == NULLFILE)
  250.         return;
  251.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  252.         return;
  253.     if((size = fread(bp->data,1,cnt,s->upload)) > 0){
  254.         bp->cnt = (int16)size;
  255.         send_tcp(tcb,bp);
  256.     } else {
  257.         free_p(bp);
  258.     }
  259.     if(size != cnt){
  260.         /* Error or end-of-file */
  261.         fclose(s->upload);
  262.         s->upload = NULLFILE;
  263.         free(s->ufile);
  264.         s->ufile = NULLCHAR;
  265.     }
  266. }
  267.  
  268. /* State change upcall routine */
  269. static void
  270. t_state(tcb,old,new)
  271. register struct tcb *tcb;
  272. char old,new;
  273. {
  274.     struct telnet *tn;
  275.     char notify = 0;
  276.  
  277.     /* Can't add a check for unknown connection here, it would loop
  278.      * on a close upcall! We're just careful later on.
  279.      */
  280.     tn = (struct telnet *)tcb->user;
  281.  
  282.     if(Current != NULLSESSION && Current->type == TELNET && Current->cb.telnet == tn)
  283.     {
  284.         notify = 1;
  285.         cooked();       /* prettify things... -- hyc */
  286.     }
  287.  
  288.     switch(new){
  289.     case TCP_CLOSE_WAIT:
  290.         if(notify)
  291.             printf("%s\n",Tcpstates[new]);
  292.         close_tcp(tcb);
  293.         break;
  294.     case TCP_CLOSED:    /* court adjourned */
  295.         if(notify){
  296.             printf("%s (%s",Tcpstates[new],Tcpreasons[tcb->reason]);
  297.             if(tcb->reason == NETWORK){
  298.                 switch(tcb->type){
  299.                 case ICMP_DEST_UNREACH:
  300.                     printf(": %s unreachable",Unreach[tcb->code]);
  301.                     break;
  302.                 case ICMP_TIME_EXCEED:
  303.                     printf(": %s time exceeded",Exceed[tcb->code]);
  304.                     break;
  305.                 }
  306.             }
  307.             printf(")\n");
  308.             cmdmode();
  309.         }
  310.         del_tcp(tcb);
  311.         if(tn != NULLTN)
  312.             free_telnet(tn);
  313.         break;
  314.     default:
  315.         if(notify)
  316.             printf("%s\n",Tcpstates[new]);
  317.         break;
  318.     }
  319. }
  320. /* Delete telnet structure */
  321. static void
  322. free_telnet(tn)
  323. struct telnet *tn;
  324. {
  325.     if(tn->session != NULLSESSION)
  326.         freesession(tn->session);
  327.  
  328.     if(tn != NULLTN)
  329.         free((char *)tn);
  330. }
  331.  
  332. int
  333. doecho(argc,argv,p)
  334. int argc;
  335. char *argv[];
  336. void *p;
  337. {
  338.     if(argc < 2){
  339.         if(Refuse_echo)
  340.             printf("Refuse\n");
  341.         else
  342.             printf("Accept\n");
  343.     } else {
  344.         if(argv[1][0] == 'r')
  345.             Refuse_echo = 1;
  346.         else if(argv[1][0] == 'a')
  347.             Refuse_echo = 0;
  348.         else
  349.             return -1;
  350.     }
  351.     return 0;
  352. }
  353. /* set for unix end of line for remote echo mode telnet */
  354. int
  355. doeol(argc,argv,p)
  356. int argc;
  357. char *argv[];
  358. void *p;
  359. {
  360.     if(argc < 2){
  361.         if(Tn_cr_mode)
  362.             printf("null\n");
  363.         else
  364.             printf("standard\n");
  365.     } else {
  366.         if(argv[1][0] == 'n')
  367.             Tn_cr_mode = 1;
  368.         else if(argv[1][0] == 's')
  369.             Tn_cr_mode = 0;
  370.         else {
  371.             printf("Usage: %s [standard|null]\n",argv[0]);
  372.             return -1;
  373.         }
  374.     }
  375.     return 0;
  376. }
  377.  
  378. /* The guts of the actual Telnet protocol: negotiating options */
  379. static void
  380. willopt(tn,opt)
  381. struct telnet *tn;
  382. int opt;
  383. {
  384.     int ack;
  385.     void answer();
  386.  
  387. #ifdef  DEBUG
  388.     printf("recv: will ");
  389.     if(uchar(opt) <= NOPTIONS)
  390.         printf("%s\n",T_options[opt]);
  391.     else
  392.         printf("%u\n",opt);
  393. #endif
  394.  
  395.     switch(uchar(opt)){
  396.     case TN_TRANSMIT_BINARY:
  397.     case TN_ECHO:
  398.     case TN_SUPPRESS_GA:
  399.         if(tn->remote[uchar(opt)] == 1)
  400.             return;         /* Already set, ignore to prevent loop */
  401.         if(uchar(opt) == TN_ECHO){
  402.             if(Refuse_echo){
  403.                 /* User doesn't want to accept */
  404.                 ack = DONT;
  405.                 break;
  406.             } else
  407.                 raw();          /* Put tty into raw mode */
  408.         }
  409.         tn->remote[uchar(opt)] = 1;
  410.         ack = DO;
  411.         break;
  412.     default:
  413.         ack = DONT;     /* We don't know what he's offering; refuse */
  414.     }
  415.     answer(tn,ack,opt);
  416. }
  417. static void
  418. wontopt(tn,opt)
  419. struct telnet *tn;
  420. int opt;
  421. {
  422.     void answer();
  423.  
  424. #ifdef  DEBUG
  425.     printf("recv: wont ");
  426.     if(uchar(opt) <= NOPTIONS)
  427.         printf("%s\n",T_options[uchar(opt)]);
  428.     else
  429.         printf("%u\n",uchar(opt));
  430. #endif
  431.     if(uchar(opt) <= NOPTIONS){
  432.         if(tn->remote[uchar(opt)] == 0)
  433.             return;         /* Already clear, ignore to prevent loop */
  434.         tn->remote[uchar(opt)] = 0;
  435.         if(uchar(opt) == TN_ECHO)
  436.             cooked();       /* Put tty into cooked mode */
  437.     }
  438.     answer(tn,DONT,opt);    /* Must always accept */
  439. }
  440. static void
  441. doopt(tn,opt)
  442. struct telnet *tn;
  443. int opt;
  444. {
  445.     void answer();
  446.     int ack;
  447.  
  448. #ifdef  DEBUG
  449.     printf("recv: do ");
  450.     if(uchar(opt) <= NOPTIONS)
  451.         printf("%s\n",T_options[uchar(opt)]);
  452.     else
  453.         printf("%u\n",uchar(opt));
  454. #endif
  455.     switch(uchar(opt)){
  456. #ifdef  FUTURE  /* Use when local options are implemented */
  457.         if(tn->local[uchar(opt)] == 1)
  458.             return;         /* Already set, ignore to prevent loop */
  459.         tn->local[uchar(opt)] = 1;
  460.         ack = WILL;
  461.         break;
  462. #endif
  463.     default:
  464.         ack = WONT;     /* Don't know what it is */
  465.     }
  466.     answer(tn,ack,opt);
  467. }
  468. static void
  469. dontopt(tn,opt)
  470. struct telnet *tn;
  471. int opt;
  472. {
  473.     void answer();
  474.  
  475. #ifdef  DEBUG
  476.     printf("recv: dont ");
  477.     if(uchar(opt) <= NOPTIONS)
  478.         printf("%s\n",T_options[uchar(opt)]);
  479.     else
  480.         printf("%u\n",uchar(opt));
  481. #endif
  482.     if(uchar(opt) <= NOPTIONS){
  483.         if(tn->local[uchar(opt)] == 0){
  484.             /* Already clear, ignore to prevent loop */
  485.             return;
  486.         }
  487.         tn->local[uchar(opt)] = 0;
  488.     }
  489.     answer(tn,WONT,opt);
  490. }
  491. static
  492. void
  493. answer(tn,r1,r2)
  494. struct telnet *tn;
  495. int r1,r2;
  496. {
  497.     struct mbuf *bp;
  498.     char s[3];
  499.  
  500. #ifdef  DEBUG
  501.     switch(r1){
  502.     case WILL:
  503.         printf("sent: will ");
  504.         break;
  505.     case WONT:
  506.         printf("sent: wont ");
  507.         break;
  508.     case DO:
  509.         printf("sent: do ");
  510.         break;
  511.     case DONT:
  512.         printf("sent: dont ");
  513.         break;
  514.     }
  515.     if(r2 <= 6)
  516.         printf("%s\n",T_options[r2]);
  517.     else
  518.         printf("%u\n",r2);
  519. #endif
  520.  
  521.     s[0] = IAC;
  522.     s[1] = r1;
  523.     s[2] = r2;
  524.     bp = qdata(s,(int16)3);
  525.     send_tcp(tn->tcb,bp);
  526. }
  527.